#ifndef PARALLEL_ARITHMETIC_OPERATION_MODEL_GENERATOR_H_JM_20120813
#define PARALLEL_ARITHMETIC_OPERATION_MODEL_GENERATOR_H_JM_20120813
/** @file ParallelArithmeticOperationModelGenerator.h
 * Generator modelu pre aritmeticke operacie. 
 **/
#include "ModelGenerator.h"
#include "Slices.h"

namespace jm4bbx {
	/** Generator modelu pre aritmeticke operacie. Vygenerovany model 
	 * paralelizuje len samotne vykonanie operacie. Stupen paralelizacie sa 
	 * zadava ako parameter sablony.
	 * 
	 * Priklad generovaneho modelu pre paralelizacny faktor N == 4.
	 * @verbatim
	 *                            fork            merge
	 *                               ______##______
	 *                              |      ##      |
	 *                              |  operations  |
	 *            load    start     |______##______|    stop    output
 	 *    input   data    timer     |      ##      |    timer    data   output
	 *     ##______##______##______##             ##______##______##______##
	 *     ##      ##      ##      ##             ##      ##      ##      ##
	 *                              |______##______|
	 *                              |      ##      |
	 *                              |              |
	 *                              |______##______|
	 *                                     ##
	 * @endverbatim                                    
	 *                     
	 * Generator je mozne ciastocne konfigurovat. Urcit je mozne box, ktory 
	 * ziska-nacita data pre spracovanie. Dalej je nastavitelny box pre samotne 
	 * operacie a tiez vystupny box, ktory vysledky operacie naslene zapise.
	 * Generatoru je tiez potrebne predat pomenovanie typu spracovavanych 
	 * hodnot. V pripade potreby je mozne zmeni pocty vstupnych a vystupnych 
	 * stlpcov, ktore si boxy posielaju (defaultne su 2 stlpce pre operandy a 
	 * 1 stlpec pre vysledok).
	 * 
	 * Nesatvitelne su box vstypu a vystupu vypoctu modelu, rozvetvenie (fork) 
	 * vypoctu, zliatie (merge) vypoctu a boxy casovacov, ktore meraju cas 
	 * vypoctu.
	 * 
	 * @tparam N stupen paralelizacie
	 **/

	template<int N>
	class ParallelArithmeticOperationModelGenerator : public ModelGenerator {
	public:

		/**
		 * Nastavitelne su len niektore vlastnosti generatora a to vstup dat, 
		 * vystup dat, spracovanie (operacia), typ dat a pocty stlpcov.
		 * 
		 * @param inputBoxName meno boxu, ktory nacita data na spracovanie
		 * @param operationBoxName meno boxu, ktory vykona potrebnu operaciu
		 * @param outputBoxName meno boxu, ktory zapise vysledky
		 * @param typeName meno typu spracovavanych dat
		 * @param operandColumns pocet stlpcov, ktore vstupuju do operacie ako 
		 *		  operandy
		 * @param resultColumn pocet stlpcov, do ktorych sa ulozi vysledok 
		 *		  operacie
		 **/
		ParallelArithmeticOperationModelGenerator(
			const std::string& inputBoxName, 
			const std::string& operationBoxName,
			const std::string& outputBoxName,
			const std::string& typeName,
			const int operandColumns = 2,
			const int resultColumns = 1)  {

				const int columns = operandColumns + resultColumns;

				BoxDescriptorPtr loadData = addBox(inputBoxName);
				BoxDescriptorPtr startTimer = addBox("Timer");
				BoxDescriptorPtr fork = addBox("Fork", genBoxParam("forkFactor", N));
				BoxDescriptorPtr merge = addBox("Merge", genBoxParam("mergeFactor", N));
				BoxDescriptorPtr stopTimer = addBox("Timer");
				BoxDescriptorPtr output = addBox(outputBoxName);
				BoxDescriptorPtr operations = addBox(operationBoxName, N);


				addSlice<PlainSlice>(getModelInputId(), loadData->getBoxId());


				addSlice<PlainSlice>(loadData->getBoxId(), 
					startTimer->getBoxId(), genTypes(typeName, columns));

				addSlice<PlainSlice>(startTimer->getBoxId(), fork->getBoxId(), 
					genTypes(typeName, columns));

				addSlice<ForkSlice<N>>(fork->getBoxId(), 
					operations->getBoxIds(), genTypes(typeName, columns));

				addSlice<MergeSlice<N>>(operations->getBoxIds(), 
					merge->getBoxId(), genTypes(typeName, resultColumns));

				addSlice<PlainSlice>(merge->getBoxId(), stopTimer->getBoxId(), 
					genTypes(typeName, resultColumns));

				addSlice<PlainSlice>(stopTimer->getBoxId(), 
					output->getBoxId(), genTypes(typeName, resultColumns));

				addSlice<PlainSlice>(output->getBoxId(), getModelOutputId());
		}

	};

} // namespace jm4bbx 

#endif
